#include "Agent.h"
#include "BehaviorTree.h"
#include "AgentManager.h"

Agent::Agent()
{
}

Agent::~Agent()
{
}

void Agent::Initialize(std::vector<std::vector<Node*>> &pGrid)
{	
	m_xDisplayManager = DisplayManager::GetInstance();
	m_xSpriteManager = SpriteManager::GetInstance();

	Grid = pGrid;

	m_bReachedTarget = true;
	m_bFinishedPath = true;
	m_xTargetNode = nullptr;
	m_fCheckRange = 1.0f;
	m_iPathID = 0;

	//BehaviorNode
	

	m_fKeyboardDelay = 0.0f;
	m_fIdleTimer = 0.0f;

	m_fHunger = 25.0f;
	m_bKill = false;

	m_vSize = sf::Vector2f(40.0f, 40.0f);
}

void Agent::Update(float pDeltaTime)
{
	// If the agent has not reached the current target
	if (!m_bFinishedPath)
	{
		if (!m_bReachedTarget)
		{
			// Check if the agent is within certain range of the target.
			if ((m_vPosition.x >= (m_vTargetPosition.x - m_fCheckRange)) && (m_vPosition.x <= (m_vTargetPosition.x + m_fCheckRange)) &&
				(m_vPosition.y >= (m_vTargetPosition.y - m_fCheckRange)) && (m_vPosition.y <= (m_vTargetPosition.y + m_fCheckRange)))
			{
				// Reached the target

				m_bReachedTarget = true;

				m_xCurrentNode->RemoveAgent(this);
				m_xTargetNode->AddAgent(this);

				m_xCurrentNode = m_xTargetNode;
				if (m_iPathID == (m_vPath.size() - 1))
				{
					m_bFinishedPath = true;
				}
				else
				{
					m_iPathID++;
				}
			}
			else
			{
				// Move to the target
				Move((m_vTargetPosition - m_vPosition) * m_fMoveSpeed * pDeltaTime);
			}
		}
		// Next node in the list
		else if (m_bReachedTarget)
		{
			m_bReachedTarget = false;
			m_xTargetNode = m_vPath[m_iPathID];
			m_vTargetPosition = m_xTargetNode->m_vPosition;
		}
	}

	//m_xSprite->setColor(sf::Color(0, 0,0, 255));

	if (m_fHunger > 0.0f)
	{
		m_fHunger -= pDeltaTime;
	}
	else if (m_fHunger <= 0.0f)
	{
		m_bKill = true;
	}


	sf::Vector2f mousePos = (sf::Vector2f)InputHandler::GetInstance()->GetMousePosition();

	if (InputHandler::GetInstance()->isMouseDownFirst(sf::Mouse::Left))
	{
		if ((mousePos.x < (m_vPosition.x + m_vSize.x / 2)) && (mousePos.x > m_vPosition.x - m_vSize.x / 2))
		{
			if ((mousePos.y < (m_vPosition.y + m_vSize.y / 2)) && (mousePos.y > m_vPosition.y - m_vSize.y / 2))
			{
				float Distance = PointDistance(AgentManager::GetInstance()->GetPlayer()->GetPosition(), mousePos);
				//std::cout << "Clicked " << Distance << std::endl;
				if (Distance <= 200.0f)
				{
					m_bKill = true;
				}
			}
		}
	}

	GameObject::Update(pDeltaTime);
}

void Agent::Cleanup()
{ 
	for (int i = 0; i < m_CData.m_SearchDataList.size(); i++)
	{
		delete 	m_CData.m_SearchDataList[i];
		m_CData.m_SearchDataList[i] = nullptr;

	}
	m_CData.m_SearchDataList.clear();
	m_CData.ClosestThreat = nullptr;
	m_CData.ClosestFood = nullptr;

	m_xCurrentNode->RemoveAgent(this);
	for (int i = 0; i < m_vPath.size(); i++)
	{
		if (m_vPath[i]->m_xRect != nullptr)
		{
			m_vPath[i]->m_xRect->setFillColor(sf::Color::Transparent);
		}
	}
	GameObject::Cleanup();
}

void Agent::SetCurrentNode(Node* pNode)
{
	m_xCurrentNode = pNode;
	m_xCurrentNode->AddAgent(this);
}
//void Agent::SearchArea()
//{
//	// Find somewhere to go.
//	// Look at all the nodes in the sense range and add anything interesting to a list
//	Think();
//}

//void Agent::Think()
//{
//	// Evaluate options
//	// Look through the list of interesting things and find the best one for the agent to do
//	Act();
//}

//void Agent::Act()
//{
//	// Interact with objects
//	// If the target is not within range to interact with travel to the node and then interact
//
//	// Find random path
//	if (m_bFinishedPath)
//	{
//		sf::Vector2i curNodeID = m_xCurrentNode->m_vID;
//
//		// Find a random node within the sense range and find a path too that node.
//		bool foundTarget = false;
//		while (!foundTarget)
//		{
//			int RandX = rand() % ((m_iSenseRange * 2) + 1) + (-m_iSenseRange);
//			int RandY = rand() % ((m_iSenseRange * 2) + 1) + (-m_iSenseRange);
//
//			if ((curNodeID.x + RandX <= 29) && (curNodeID.x + RandX >= 0) && (curNodeID.y + RandY <= 29) && (curNodeID.y + RandY >= 0))
//			{
//				if ((Grid[curNodeID.x + RandX][curNodeID.y + RandY]->m_bBlocked == false))
//				{
//					FindPath(Grid[curNodeID.x + RandX][curNodeID.y + RandY]);
//					foundTarget = true;
//				}
//			}
//		}
//		std::cout << "Found Goal" << std::endl;
//	}
//}

bool Agent::FindPath(Node* pNode)
{
	// Clears the previous path of it's fill color
	for (int i = 0; i < m_vPath.size(); i++)
	{
		m_vPath[i]->m_xRect->setFillColor(sf::Color::Transparent);
	}

	// Find path to node
	m_vPath = aStar.Setup(m_xCurrentNode, pNode);
	if (m_vPath.size() > 0)
	{
		// Flip the path so that it begins by thep layer
		std::reverse(m_vPath.begin(), m_vPath.end());

		// Paint path
		for (int i = 0; i < m_vPath.size(); i++)
		{
			m_vPath[i]->m_xRect->setFillColor(sf::Color(255, 255, 255, 50));
		}
		m_vPath.back()->m_xRect->setFillColor(sf::Color(250, 100, 250, 50));

		return true;
	}

	return false;
}

void Agent::Travel()
{
	// Travel to node
	if (m_vPath[0] != nullptr)
	{
		m_xTargetNode = m_vPath[0];
		m_vTargetPosition = m_xTargetNode->m_vPosition;
		m_bReachedTarget = false;
		m_bFinishedPath = false;
		m_iPathID = 0;
	}
	else
	{
		std::cout << "ERROR - TRAVEL" << std::endl;
	}
}
void Agent::SearchArea2()
{
	for (int i = 0; i < m_CData.m_SearchDataList.size(); i++)
	{
		delete 	m_CData.m_SearchDataList[i];
		m_CData.m_SearchDataList[i] = nullptr;

	}
	m_CData.m_SearchDataList.clear();
	m_CData.ClosestThreat = nullptr;
	m_CData.ClosestFood = nullptr;

	Node* TempNode = nullptr;
	NodeSenseData* Data = new NodeSenseData;
	Data->m_Node = m_xCurrentNode;
	m_CData.m_SearchDataList.push_back(Data);
	int topLeftIdX = m_xCurrentNode->m_vID.x - m_iSenseRange;
	int topLeftIdY = m_xCurrentNode->m_vID.y - m_iSenseRange;

	for (int x = 0; x <m_iSenseRange*2+1; x++)
	{
		for (int y = 0; y < m_iSenseRange*2+1; y++)
		{
			if ((topLeftIdX + x <= 29) && (topLeftIdX + x >= 0) && (topLeftIdY + y <= 29) && (topLeftIdY + y >= 0))
			{
				TempNode = Grid[x + topLeftIdX][y + topLeftIdY];
				if (TempNode != nullptr)
				{
					if (TempNode->m_bBlocked != true)
					{
						//TempNode->m_xRect->setFillColor(sf::Color::Yellow);
					
					//	if (TempNode->m_vAgents.size()  > 0|| TempNode->m_xWorldObject != nullptr)
					//	{wawwwwwwwwwwww
							NodeSenseData* TempData1 = new NodeSenseData;
							TempData1->m_Node = TempNode;
							m_CData.m_SearchDataList.push_back(TempData1);
						
					}
				}
			}
		}
	}
	/*m_xCurrentNode->m_xRect->setFillColor(sf::Color::Black);*/
}


void Agent::Wander()
{
	m_bReachedTarget = false;

	bool newObjective = false;
	
	int direction = 0;
	while (!newObjective)
	{
		direction = rand() % 5;

		switch (direction)
		{
			// Up
			case 1:
				if (m_xCurrentNode->m_xAdjacentNodes[0] != nullptr)
				{
					newObjective = true;
					m_vTargetPosition = m_xCurrentNode->m_xAdjacentNodes[0]->m_vPosition;
					m_xCurrentNode = m_xCurrentNode->m_xAdjacentNodes[0];
				}
			break;

			// Down
			case 2:
				if (m_xCurrentNode->m_xAdjacentNodes[1] != nullptr)
				{
					newObjective = true;
					m_vTargetPosition = m_xCurrentNode->m_xAdjacentNodes[1]->m_vPosition;
					m_xCurrentNode = m_xCurrentNode->m_xAdjacentNodes[1];
				}
			break;

			// Left
			case 3:
				if (m_xCurrentNode->m_xAdjacentNodes[2] != nullptr)
				{
					newObjective = true;
					m_vTargetPosition = m_xCurrentNode->m_xAdjacentNodes[2]->m_vPosition;
					m_xCurrentNode = m_xCurrentNode->m_xAdjacentNodes[2];
				}
			break;

			//Right
			case 4:
				if (m_xCurrentNode->m_xAdjacentNodes[3] != nullptr)
				{
					newObjective = true;
					m_vTargetPosition = m_xCurrentNode->m_xAdjacentNodes[3]->m_vPosition;
					m_xCurrentNode = m_xCurrentNode->m_xAdjacentNodes[3];
				}
			break;
		}
	}
}

double Agent::PointDistance(sf::Vector2f pPointA, sf::Vector2f pPointB)
{
	int X = (pPointB.x - pPointA.x) * (pPointB.x - pPointA.x);
	int Y = (pPointB.y - pPointA.y) * (pPointB.y - pPointA.y);

	double distance = sqrt((double)X + Y);

	return distance;
	return 0;
}
